package com.shuyu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shuyu.common.constant.Constants;
import com.shuyu.common.core.domain.entity.Customer;
import com.shuyu.common.core.redis.RedisCache;
import com.shuyu.common.exception.ServiceException;
import com.shuyu.common.utils.SecurityUtils;
import com.shuyu.common.utils.StringUtils;
import com.shuyu.common.utils.nft.NFTUtils;
import com.shuyu.common.utils.sign.Md5Utils;
import com.shuyu.domain.*;
import com.shuyu.mapper.CustomerAssetsMapper;
import com.shuyu.service.*;
import com.shuyu.vo.CardInfoVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CustomerAssetsServiceImpl extends ServiceImpl<CustomerAssetsMapper,CustomerAssets> implements CustomerAssetsService {
    @Resource
    private NFTService nftService;
    @Resource
    private NftTransferService nftTransferService;
    @Resource
    private ProductService productService;
    @Resource
    private CustomerService customerService;
    @Resource
    private ProductCardCodeService productCardCodeService;
    @Resource
    private CustomerPointService customerPointService;
    @Resource
    private CustomerCardTransferService customerCardTransferService;
    @Resource
    private RedisCache redisCache;


    @Override
    public CardInfoVo storage(String code) {
        ProductCardCode productCardCode = productCardCodeService.getOne(new LambdaUpdateWrapper<ProductCardCode>().eq(ProductCardCode::getCollectionCode, code));
        Long userId = SecurityUtils.getLoginUser().getUserId();
        Customer customer = customerService.getById(userId);
        //校验用户是否实名认证了
        String idCard = customer.getIdCard();
        if(StringUtils.isNotEmpty(idCard)){
            throw new ServiceException("用户还未实名认证，请先实名认证",2001);
        }
        Integer nftId = null;
        int productId;
        CardInfoVo cardInfoVo;

        if(productCardCode != null){
            productId = productCardCode.getProductId();
            String transactionHash = productCardCode.getTransactionHash();
            Product product = productService.getById(productId);
            int point = product.getPoint();
            if(StringUtils.isNotEmpty(transactionHash)){//说明有ntf
                NFT nft = nftService.getById(productCardCode.getNftId());
                //判断NFT卡牌是否有被激活
                if(productCardCode.getActiveStatus()==1){
                    //判断用户扫卡用户跟拥有卡牌用户是否是同一人
                    NftTransfer transfer = nftTransferService.getOne(new LambdaQueryWrapper<NftTransfer>().eq(NftTransfer::getNftId, nft.getId())
                            .orderByDesc(NftTransfer::getTransferTime).last("limit 1"));
                    //如果拥有者跟扫码者是同一个人 提示 卡牌已经被使用
                    if(customer.getWallet().equals(transfer.getToAddress())){
                        throw new ServiceException("卡牌编码已被使用，请更换重试",3001);
                    }else {//如果拥有者跟扫码者不是是同一个人 这表示这张卡牌正在进行交易
                        int count1 = customerCardTransferService.count(new LambdaQueryWrapper<CustomerCardTransfer>().eq(CustomerCardTransfer::getCollectionCode, code)
                                .eq(CustomerCardTransfer::getStatus,"交易中").ne(CustomerCardTransfer::getToCustomerId,userId));
                        if(count1>0) {
                            throw new ServiceException("卡牌正在被其他用户交易", 3002);
                        }
                        Customer one = customerService.getOne(new LambdaQueryWrapper<Customer>().eq(Customer::getWallet, transfer.getToAddress()));
                        cardInfoVo = new CardInfoVo();
                        cardInfoVo.setMobile(one.getMobile());
                        cardInfoVo.setCollectionCode(code);
                        cardInfoVo.setNickname(one.getNickname());
                        int count = customerCardTransferService.count(new LambdaQueryWrapper<CustomerCardTransfer>().eq(CustomerCardTransfer::getCollectionCode, code)
                                .eq(CustomerCardTransfer::getStatus,"交易中").eq(CustomerCardTransfer::getToCustomerId,userId));
                        if(count==0){
                            cardInfoVo.setRecordStatus(0);
                        }else {
                            cardInfoVo.setRecordStatus(1);
                        }
                        return cardInfoVo;
                    }
                }
                nft.setActiveStatus(1);
                nft.setWallet(customer.getWallet());
                try {
                    String transactionHash2 = NFTUtils.transactionNFT(Constants.WALLET_ADDRESS, Constants.PRIVATE_KEY, customer.getWallet(), nft.getTokenId());
                    nftService.updateById(nft);
                    NftTransfer nftTransfer = new NftTransfer(nft.getId(), transactionHash2, nft.getTokenId(), Constants.WALLET_ADDRESS, customer.getWallet(), "transfer", new Date(),customer.getNickname());
                    nftTransferService.save(nftTransfer);
                }catch (Exception e){
                    e.printStackTrace();
                }
                saveCustomerAssets(userId, product.getProductId(), 1, nft.getId(),1, null);
                Product nftProduct = productService.getById(product.getProductId());
//                customerService.updateCustomerAssets(ProductType.NFT.type, product.getProductId(), userId);
                cardInfoVo = new CardInfoVo(1, nftProduct.getImg(), nftProduct.getIssuingCompany(), nftProduct.getProductionCompany(), nftProduct.getIntroduction(), point);
                List<NftTransfer> nftTransferList = nftTransferService.list(new LambdaQueryWrapper<NftTransfer>().eq(NftTransfer::getNftId, nft.getId()).orderByAsc(NftTransfer::getTransferTime));
                cardInfoVo.setNftTransferList(nftTransferList);
                saveCustomerAssets(userId, productId, 2, 0,2, code);
            }else {
                if(productCardCode.getActiveStatus()==1){
                    throw new ServiceException("卡牌编码已被使用，请更换重试",3001);
                }
                cardInfoVo = new CardInfoVo(2, null, null, null, null, point);
            }
            productCardCode.setActiveStatus(1);
            productCardCodeService.updateById(productCardCode);
            if(point>0){
                Integer totalPoint = point+customer.getPoint();
                customer.setPoint(totalPoint);
                customerService.updateById(customer);
                CustomerPoint customerPoint = new CustomerPoint(customer.getId(), point, productId, 1, new Date());
                customerPointService.save(customerPoint);
            }

//            customerService.updateCustomerAssets(ProductType.卡牌.type, productId, userId);
        }else {
//            Product product = productService.getOne(new LambdaUpdateWrapper<Product>().eq(Product::getCardSerial, code));
//            if(product == null){
//                throw new ServiceException("卡牌编码异常");
//            }
//            productId = product.getId();
//            saveCustomerAssets(userId, productId, 2, 0,2);
            cardInfoVo = new CardInfoVo(2, null, null, null, null, 0);
//            customerService.updateCustomerAssets(ProductType.卡牌.type, productId, userId);
        }
        return cardInfoVo;
    }

    /**
     *
     * @param userId 用户ID
     * @param productId 产品ID
     * @param nftId NFTID
     * @param assetsType 资产类型 1NFT 2卡牌 3MV 4积分
     */
    private void saveCustomerAssets(long userId, int productId,int productType, int nftId, int assetsType, String collectionCode){
        CustomerAssets customerAssets = new CustomerAssets(userId, productId, productType, new Date(), nftId, assetsType, collectionCode);
        this.save(customerAssets);
    }

    @Override
    public List<CustomerAssets> getBag(int type) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        List<CustomerAssets> list = this.list(new LambdaQueryWrapper<CustomerAssets>()
                .eq(CustomerAssets::getAssetsType, type)
                .eq(CustomerAssets::getCustomerId, userId));

        for (CustomerAssets customerAssets : list) {
            Integer productId = customerAssets.getProductId();
            Product product = productService.getById(productId);
            if(product == null){
                continue;
            }
            customerAssets.setProductName(product.getName());
            customerAssets.setImg(product.getImg());
            customerAssets.setProduct(product);
            if(type == 1){
                Integer nftId = customerAssets.getNftId();
                List<NftTransfer> nftTransferList = nftTransferService.list(new LambdaQueryWrapper<NftTransfer>().eq(NftTransfer::getNftId, nftId).orderByAsc(NftTransfer::getTransferTime));
                customerAssets.setNftTransferList(nftTransferList);
                if(nftTransferList.get(0).getTokenId()!=null){
                    String collectionCode = Md5Utils.hash(nftTransferList.get(0).getTokenId().toString()+"didol"+productId);
                    customerAssets.setCollectionCode(collectionCode);
                }
            }
        }
        return list;
    }

    @Override
    public List<Customer> getCustomerAssets(String username) {
        String condition = "where t2.del_flag = 0 ";
        if(StringUtils.isNotEmpty(username)){
            condition = " and t2.username like '%"+username+"%' ";
        }
        List<Customer> list = this.baseMapper.getCustomerAssets(condition);
        return list;

    }

    @Override
    public void startTransactionNFT(String collectionCode, Long userId) {
        ProductCardCode productCardCode = productCardCodeService.getOne(new LambdaUpdateWrapper<ProductCardCode>().eq(ProductCardCode::getCollectionCode, collectionCode));
        int count = customerCardTransferService.count(new LambdaQueryWrapper<CustomerCardTransfer>().eq(CustomerCardTransfer::getCollectionCode, collectionCode)
                .eq(CustomerCardTransfer::getStatus,"交易中").eq(CustomerCardTransfer::getToCustomerId,userId));
        if(count==0) {
            Customer customer = customerService.getById(userId);
            NFT nft = nftService.getById(productCardCode.getNftId());
            NftTransfer transfer = nftTransferService.getOne(new LambdaQueryWrapper<NftTransfer>().eq(NftTransfer::getNftId, nft.getId())
                    .orderByDesc(NftTransfer::getTransferTime).last("limit 1"));
            Customer one = customerService.getOne(new LambdaQueryWrapper<Customer>().eq(Customer::getWallet, transfer.getToAddress()));
            CustomerCardTransfer customerCardTransfer = new CustomerCardTransfer(nft.getId(), nft.getTokenId(), one.getNickname(), one.getId(), customer.getNickname(), userId, collectionCode, transfer.getTransactionHash(), new Date(), "交易中");
            customerCardTransferService.save(customerCardTransfer);
        }
    }

    @Override
    public void transactionNFT(Long userId) {
        CustomerCardTransfer customerCardTransfer = customerCardTransferService.getOne(new LambdaQueryWrapper<CustomerCardTransfer>()
                .eq(CustomerCardTransfer::getToCustomerId, userId)
                .eq(CustomerCardTransfer::getStatus, "交易中"));
        customerCardTransferService.updateById(customerCardTransfer);
        Customer customer = customerService.getById(userId);
        Customer fromCustomer = customerService.getById(customerCardTransfer.getFromCustomerId());
        try {
            NFT nft = nftService.getById(customerCardTransfer.getNftId());
            nft.setWallet(customer.getWallet());
            String toAddress = customer.getWallet();
            String fromAddress = fromCustomer.getWallet();
            String privateKey = fromCustomer.getPrivateKey();
            String transactionHash2 = NFTUtils.transactionNFT(fromAddress, privateKey, toAddress, nft.getTokenId());
            nftService.updateById(nft);
            NftTransfer nftTransfer = new NftTransfer(nft.getId(), transactionHash2, nft.getTokenId(), fromAddress, toAddress, "transfer", new Date(),customer.getNickname());
            nftTransferService.save(nftTransfer);
        }catch (Exception e){
            e.printStackTrace();
        }

        this.update(new LambdaUpdateWrapper<CustomerAssets>().set(CustomerAssets::getCustomerId,userId).eq(CustomerAssets::getCollectionCode, customerCardTransfer.getCollectionCode()));
        this.update(new LambdaUpdateWrapper<CustomerAssets>().set(CustomerAssets::getCustomerId,userId).eq(CustomerAssets::getNftId, customerCardTransfer.getNftId()));

        customerCardTransfer.setFinishTime(new Date());
        customerCardTransfer.setStatus("已完成");
        customerCardTransferService.updateById(customerCardTransfer);
    }

    private String getProductName(List<String> productIds){
        List<Product> productList = productService.list(new LambdaQueryWrapper<Product>().in(Product::getId, productIds));
        List<String> productNameList = productList.stream().map(Product::getName).collect(Collectors.toList());
        String name = StringUtils.join(productNameList, ",");
        return name;
    }
}
